<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2"
	xmlns:xf="http://www.w3.org/2002/xforms"
	exclude-result-prefixes="xsd xsl"> 
	
	<xsl:import href="global-vars.xsl"/>
	<xsl:import href="global-templates.xsl"/>
	<xsl:import href="AmountType.xsl" />
	<xsl:import href="BinaryObjectType.xsl" />
	<xsl:import href="CodeType.xsl" />
	<xsl:import href="IDType.xsl" />
	<xsl:import href="MeasureType.xsl" />
	<xsl:import href="NameType.xsl" />
	<xsl:import href="QuantityType.xsl" />
	<xsl:import href="TextType.xsl" />

	<xsl:template name="GenerateBindings">
		<xsl:param name="element.root" />
		<xsl:param name="element.root.type" />
		
		<xsl:variable name="ref" select="concat('/', $global.schema.root.prefix, ':', $element.root )" />
		
		<xsl:call-template name="GenerateElementBindings">
			<xsl:with-param name="element.type" select="$element.root.type" />
			<xsl:with-param name="element.ref" select="$ref" />
			<xsl:with-param name="element.prefix"><xsl:value-of 
				select="$global.schema.root.prefix" /></xsl:with-param>
		</xsl:call-template>
	</xsl:template>
	
	<!-- 
		This template generates the bindings for all BBIE's from the message schema's and for the
		ABIE's that may occur more than once.
	-->
	<xsl:template name="GenerateElementBindings">
		<xsl:param name="element.type" />
		<xsl:param name="element.ref" />
		<xsl:param name="element.schema" />
		<xsl:param name="element.prefix" />
		
		<xsl:if test="if( not( contains( $element.type, ':') ) )
			then error( QName( 'E', 'E' ), concat( 'bindings.xsl : GenerateElementBindings : element.type must contain a prefix - value = ', $element.type ) )
			else true()" />
		
		<!--
			All elements that are childelements from the element of type "elementType". For an example of this
			look in the message schema's for a <xsd:complexType name="{TYPE}"> declaration. The type is the
			same as elementType with the exception that elementType also contains the prefix from the 
			namespace in which it is declared.
		-->
		<xsl:variable name="element.children">
			<xsl:call-template name="GetChildElements">
				<xsl:with-param name="parent" select="substring-after( $element.type, ':' )" />
				<xsl:with-param name="parent.schema" select="$element.schema" />
			</xsl:call-template>			
		</xsl:variable>
		
		<!-- 
			Iterate over the childs from the the element of type "elementType".
		-->
		<xsl:for-each select="$element.children/xsd:element">
			<xsl:variable name="element.child.ref" select="concat( $element.ref, '/', $element.prefix, ':', @name )" />
			<xsl:variable name="countstatement" select="concat( 'following-sibling::', $element.prefix, ':', @name )" />
			
			<xsl:choose>
				<!--
					Handle BBIE's.
					
					If an element can occur more than one time it should be in a repeat element. To handle a 
					repeat element cleanly, there should always be one element that serves as a template for
					newly created elements. This one is not relevant for the 	message (and will therefore not
					be send) but it is needed as template for new elements. The last element in the model is
					used for this. 
				-->
				<xsl:when test="xsd:annotation/xsd:documentation/ccts:Acronym = 'BBIE'">
					<xsl:element name="xf:bind">
						<xsl:attribute name="nodeset" select="$element.child.ref " />
						<xsl:attribute name="type" select="@type" />
						<xsl:if test="@maxOccurs = 'unbounded' or @maxOccurs > 1">
							<xsl:attribute name="relevant">count( <xsl:value-of select="$countstatement" /> ) &gt; 0</xsl:attribute>
						</xsl:if>
					</xsl:element>
					<!-- 
						At this moment we have a qualified or unqualified datatype. The bindings that are
						defined for the unqualified datatypes should be looked up here.
					-->
					<xsl:variable name="element.type.schema">
						<xsl:call-template name="GetDataTypeDocument">
							<xsl:with-param name="element.type" select="@type" />
							<xsl:with-param name="element.schema" select="$element.schema" />
						</xsl:call-template>
					</xsl:variable>
					<xsl:call-template name="HandleBBIE">
						<xsl:with-param name="bbie.type" select="@type" />
						<xsl:with-param name="bbie.schema" select="$element.type.schema" />
						<xsl:with-param name="bbie.ref" select="$element.child.ref" />
					</xsl:call-template>
				</xsl:when>
				<!-- 
					At this point the stylesheet is handling an ABIE or an ASBIE. If the ABIE or ASBIE may occur
					more than once a binding should be created for it. Otherwise it only has to be recursivly
					processed.
				-->
				<xsl:otherwise>
					<xsl:variable name="element.child.ns" 
						select="namespace-uri-for-prefix( substring-before( @type, ':' ), . )"/>
					<xsl:variable name="element.ns" select="if( $element.schema = '' ) 
						then document( $global.schema.root )/xsd:schema/@targetNamespace
						else document( $element.schema )/xsd:schema/@targetNamespace"/>
					
					<xsl:if test="@maxOccurs = 'unbounded' or @maxOccurs > 1">
						<xsl:element name="xf:bind">
							<xsl:attribute name="nodeset" select="$element.child.ref " />
							<xsl:attribute name="relevant">count( <xsl:value-of select="$countstatement" /> ) &gt; 0</xsl:attribute>
						</xsl:element>
					</xsl:if>
					
					<xsl:choose>
						<!-- 
							Test if the child element is declared in the same namespace as it's parent. If not then
							we'll have to look in which document the namespace (and thus the element) is declared.
							Also we'll have to look which prefix is used for that namespace.
						-->
						<xsl:when test="$element.ns != $element.child.ns">
							<xsl:variable name="element.type.schema">
								<xsl:call-template name="GetDataTypeDocument">
									<xsl:with-param name="element.type" select="@type" />
									<xsl:with-param name="element.schema" select="$element.schema" />
								</xsl:call-template>
							</xsl:variable>
							<xsl:variable name="element.type.prefix" select="substring-before( @type, ':' )"/>
							
							<xsl:call-template name="GenerateElementBindings">
								<xsl:with-param name="element.type" select="@type"/>
								<xsl:with-param name="element.schema" select="$element.type.schema" />
								<xsl:with-param name="element.ref" select="$element.child.ref" />
								<xsl:with-param name="element.prefix" select="$element.type.prefix"/>
							</xsl:call-template>
						</xsl:when>
						<!-- 
							The element is declared in the same document as his parent.
						-->
						<xsl:otherwise>
							<xsl:call-template name="GenerateElementBindings">
								<xsl:with-param name="element.type" select="@type"/>
								<xsl:with-param name="element.schema" select="$element.schema" />
								<xsl:with-param name="element.ref" select="$element.child.ref" />
								<xsl:with-param name="element.prefix" select="$element.prefix" />
							</xsl:call-template>
						</xsl:otherwise>
					</xsl:choose>
				</xsl:otherwise>
			</xsl:choose>
		</xsl:for-each>
	</xsl:template>
	
	<!-- 
		This template handles BBIE. It first looks if a datatype is qualified or not and then calls
		the appropriate templates to handle the (qualified) datatype.

		@param bbie.type - as the name says, the datatype of this BBIE
		@param bbie.ref - The xpath statement to reach this element in the created instance. 	
		@param bbie.schema - The document in which the datatype is declared.

	-->
	<xsl:template name="HandleBBIE">
		<xsl:param name="bbie.type" />
		<xsl:param name="bbie.ref" />
		<xsl:param name="bbie.schema" />
		
		<xsl:if test="if( not( contains( $bbie.type, ':') ) )
			then error( QName( 'E', 'E' ), concat( 'bindings.xsl : HandleBBIE : bbie.type must contain a prefix - value = ', $bbie.type ) )
			else true()" />
		
		<!-- retrieve the schema for the type of this bbie -->
		<xsl:variable name="bbie.type.schema">
			<xsl:call-template name="GetDataTypeDocument">
				<xsl:with-param name="element.type" select="$bbie.type"/>
				<xsl:with-param name="element.schema" select="$bbie.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<xsl:variable name="bbie.type.unqualified">
			<xsl:call-template name="GetUnqualifiedDataType">
				<xsl:with-param name="element.type" select="$bbie.type" />
				<xsl:with-param name="element.type.schema" select="$bbie.schema" />
			</xsl:call-template>
		</xsl:variable>
		
		<!-- remove the namespace prefix -->
		<xsl:variable name="bbie.type.unqualified" 
			select="substring-after($bbie.type.unqualified, ':')" />
		
		<xsl:choose>
			<xsl:when test="$bbie.type.unqualified = 'AmountType' ">
				<xsl:call-template name="AmountTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'BinaryObjectType'">
				<xsl:call-template name="BinaryObjectTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'CodeType'">
				<xsl:call-template name="CodeTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'IDType'">
				<xsl:call-template name="IDTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'MeasureType'">
				<xsl:call-template name="MeasureTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'NameType'">
				<xsl:call-template name="NameTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'QuantityType'">
				<xsl:call-template name="QuantityTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$bbie.type.unqualified = 'TextType'">
				<xsl:call-template name="TextTypeBinding" >
					<xsl:with-param name="bbie" select="$bbie.type" />
					<xsl:with-param name="bbie.ref" select="$bbie.ref" />
					<xsl:with-param name="bbie.schema" select="$bbie.type.schema" />
				</xsl:call-template>
			</xsl:when>
		</xsl:choose>
	</xsl:template>
</xsl:stylesheet>